using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using GameFramework;
using GameFramework.Event;
using GameFramework.Resource;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEngine;
using UnityGameFramework.Runtime;
using AppDomain = ILRuntime.Runtime.Enviorment.AppDomain;

namespace StarForce
{
    /// <summary>
    /// http组件
    /// </summary>
    public class HttpComponent : GameFrameworkComponent
    {
        /// <summary>
        /// web Ip地址
        /// </summary>
        [SerializeField] private string m_IP = "192.168.1.73";
//        [SerializeField] private string m_IP = "futian.cn.utools.club";

        /// <summary>
        /// web 端口号
        /// </summary>
        [SerializeField] private string m_Port = "8828";
//        [SerializeField] private string m_Port = "80";


        [SerializeField] private string m_FilePath = "Assets/GameMain/HotFixResources/Url/WebUrl.txt";

        public static string PublicKey = @"-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgIIlCJn5txDFKZqLH6jFbceLa1paFBf64wgi1+QTMY17IRM6lwfWmv1XTk4ZhxNIGClSUynpuDGUXMaZR4ewiVFxSYTSfE7jTdFAxy1kdd6LGSA/JMUEvUPlmi/EfFRvZ5nqSDX/4EB0XyqQJ0kPgx41cRT7NqH1XCQWTCkzxBtl+ntKvqIDjtxoB9Kmtu5+m00JjS5FuXwQ8P+sH3CC9EtECMWDA4UC5PqAWVQdmtnce3pNaUq3MwuZb2HhKD9u0TnzN
HPhjWhLyFxyHID9EvrPFQL+ginG1gInAyd1tJTtf7asX4lAiqlf1eHIehRdGMTZKKAvsFS4+1uwODgcywIDAQAB
-----END PUBLIC KEY-----";

        private LoadAssetCallbacks m_LoadAssetCallbacks;

        /// <summary>
        /// 签名
        /// </summary>
        private string m_Sign = string.Empty;

        public string Sign
        {
            get { return m_Sign; }
            set { m_Sign = value; }
        }

        /// <summary>
        /// 存储的所有Url
        /// </summary>
        private PropertyOperation m_Po;

        /// <summary>
        /// 文件是否加载完毕
        /// </summary>
        private bool m_IsLoaded;

        public bool IsLoaded
        {
            get { return m_IsLoaded; }
            set { m_IsLoaded = value; }
        }
    

        protected override void Awake()
        {
            base.Awake();
            m_LoadAssetCallbacks = new LoadAssetCallbacks(LoadAssetsSuccess, LoadAssetsFailure);
        }

        private void Start()
        {
            GameEntry.Event.Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess);
            Sign = GameEntry.Setting.GetString("Sign");
        }

        /// <summary>
        /// web回调成功事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnWebRequestSuccess(object sender, GameEventArgs e)
        {
            WebRequestSuccessEventArgs result = (WebRequestSuccessEventArgs) e;

            JObject jObject =
                (JObject) JsonConvert.DeserializeObject(Utility.Converter.GetString(result.GetWebResponseBytes()));

            Log.Info("response-" + result.UserData.ToString() + ":" + jObject);

            if (jObject == null)
            {
                return;
            }

            // todo 未授权或者登陆失效返回登陆页面
            if (jObject.ToString().Contains("code") &&
                ((int) jObject["code"] == 10404 || (int) jObject["code"] == 10401))
            {
                GameEntry.UI.OpenUIForm(2);
                m_Sign = string.Empty; 
                GameEntry.Setting.SetString("Sign", String.Empty);
            }

            //todo 接受数据回调后进行数据分发
            GameEntry.Event.Fire(sender,
                ReferencePool.Acquire<WebResponseEventArgs>().Fill(result.UserData.ToString(), jObject));
        }

        /// <summary>
        /// Post方法 
        /// </summary>
        /// <param name="jsonMap">数据</param>
        /// <param name="urlNmae">Url名称</param>
        /// <returns></returns>
        public int Post(Dictionary<string, object> jsonMap, string urlName,bool sign=true,bool isRas = true,bool isLoogEn = false)
        {
            string url = GetWebPostUrl(urlName);
//
            string jsonData = JsonString(m_Sign, jsonMap);
//
            Log.Info("request-{0}:{1}", urlName, jsonData);
//
            //加密
            
            if (isRas)
            {
                jsonData = RSAEncryption(jsonData, isLoogEn);
            
                jsonData = "{\"param\":\"" + jsonData + "\"}";
                jsonData = Utility.Text.Format("{\"param\":\" {0} \"}", jsonData);
            }
            
//
            int webId = GameEntry.WebRequest.AddWebRequest(url, Encoding.UTF8.GetBytes(jsonData), urlName);
            return webId;
            //todo 可以添加加载中的界面
        }

        /// <summary>
        /// 加解密
        /// </summary>
        /// <param name="jsonData"></param>
        /// <param name="needLongEncrypt"></param>
        /// <returns></returns>

        public static string RSAEncryption(string jsonData,bool needLongEncrypt)
        {
            using (RSACryptoServiceProvider rsaCry = PemKeyUtils.GetRSAProviderFromPemString(PublicKey))
            {
                byte[] encryptData = new byte[0];

                //todo 当字符串的长度超过117 时分割字符串 再分别加密 
                if (jsonData.Length > 117 && needLongEncrypt)
                {
                    List<string> data = SubStringByCount(jsonData, 117);

                    for (int i = 0; i < data.Count; i++)
                    {
                        Log.Info("data{0}:{1}", data[i], data[i].Length);

                        encryptData = encryptData.Concat(rsaCry.Encrypt(Utility.Converter.GetBytes(data[i]), false)).ToArray();
                    }
                }
                else
                {
                    // Debug.Log(Utility.Converter.GetBytes(jsonData));
                    // Debug.Log(Utility.Converter.GetBytes(jsonData).Length);
                    // Debug.Log(rsaCry == null);
                    // Debug.Log(rsaCry.Encrypt(Utility.Converter.GetBytes(jsonData), false));
                    encryptData = rsaCry.Encrypt(Utility.Converter.GetBytes(jsonData), false);
                }
                
                return Convert.ToBase64String(encryptData);
            }
            
        }

        public static List<string> SubStringByCount(string text , int count)
        {
            int start_index = 0; //开始索引
            int end_index = count - 1; //结束索引
            
            double count_value = 1.0 * text.Length / count;
            double newCount = Math.Ceiling(count_value); //向上取整，只有有小数就取整，比如3.14，结果4
            
            List<string> list = new List<string>();

            for (int i = 0; i < newCount; i++)
            {
                //如果end_index大于字符长度，则添加剩下字符串
                if (end_index > text.Length - 1)
                {
                    list.Add(text.Substring(start_index));

                    break;
                }
                else
                {
                    list.Add(text.Substring(start_index, count));
                    start_index += count;
                    end_index += count;
                }
            }

            return list;
        }

        public int Get(Dictionary<string, object> jsonMap, string urlName,bool sign=true)
        {
            string url = Utility.Text.Format("{0}?", GetWebPostUrl(urlName));
            string data = "";
            if (jsonMap != null)
            {
                foreach (KeyValuePair<string, object> keyValuePair in jsonMap)
                {
                    data += Utility.Text.Format("{0}={1}&", keyValuePair.Key, keyValuePair.Value);
                }

                data = data.Substring(0, data.Length - 1);
            }

            Log.Info("request-{0}:{1}", urlName, data);
            url = Utility.Text.Format("{0}{1}", url, data);
            int webId = GameEntry.WebRequest.AddWebRequest(url, urlName,sign);
            return webId;
//            http://192.168.1.73:8818/account/login?pUserId=18388888888&token=845875
        }

        /// <summary>
        /// 表单传输
        /// </summary>
        /// <param name="jsonMap">json字典</param>
        /// <param name="urlNmae">url地址</param>
        /// /// <param name="needLongEncrypt">是否需要长加密</param>
        /// <param name="sign">是否需要签名</param>
        public void Form(Dictionary<string, object> jsonMap, string urlName,bool sign=true,bool isRas = true,bool isLoogEn = false)
        {
            string url = GetWebPostUrl(urlName);
            if (jsonMap != null)
            {
                string data = "?";

                foreach (KeyValuePair<string, object> keyValuePair in jsonMap)
                {
                    data += Utility.Text.Format("{0}={1}&", keyValuePair.Key, keyValuePair.Value);
                }

                data = data.Substring(0, data.Length - 1);

                url = Utility.Text.Format("{0}{1}", url, data);
            }


            string jsonData = JsonString(m_Sign, jsonMap);
            jsonData=jsonData.Replace("{", "").Replace("}", "");
            Debug.Log("没加密的时候："+jsonData);
            //加密
            
            if (isRas)
            {
                string noJsonData = jsonData;
                jsonData = RSAEncryption(jsonData, isLoogEn);

                
                
                if (noJsonData == "")
                {
                    Debug.Log("===============================");
                    jsonData = "{\"param\":\"" + jsonData + "\"}";
                }
                else
                {
                    jsonData = "{" + noJsonData + ","+"\"param\":\"" + jsonData + "}";
                }

                Debug.Log(jsonData);
                //jsonData = Utility.Text.Format("{\"param\":\" {0} \"}", jsonData);
            }
            
            Log.Info(jsonData);
//            string encryptionString = GetWebPostUrl(jsonData);
            //TODO 利用表单进行数据传输
            WWWForm form = new WWWForm();
//            if (!isLogin)
//            {
//                form.AddField("Authorization", Sign);
//            }

            form.AddField("param", jsonData);

            GameEntry.WebRequest.AddWebRequest(url, form, urlName,sign);
        }

        public void Load()
        {
            GameEntry.Resource.LoadAsset(m_FilePath, typeof(TextAsset), Constant.AssetPriority.ImageAsset,
                m_LoadAssetCallbacks, this);
        }

        /// <summary>
        /// 获取Url
        /// </summary>
        /// <param name="urlName"></param>
        /// <returns></returns>
        public string GetWebPostUrl(string urlName)
        {
            if (!m_IsLoaded)
            {
                throw new GameFrameworkException("WebUrl not load");
            }

            return Utility.Text.Format("http://{0}:{1}{2}", m_IP, m_Port, m_Po[urlName].ToString());
        }

        /// <summary>
        /// 转换为json字符串
        /// </summary>
        /// <param name="sign"></param>
        /// <param name="jsonMap"></param>
        /// <returns></returns>
        public string JsonString(string sign, Dictionary<string, object> jsonMap)
        {
            string str = "{\"";

            if (jsonMap != null)
            {
                foreach (KeyValuePair<string, object> keyValuePair in jsonMap)
                {
                    if (keyValuePair.Value == null)
                    {
                        Log.Error(keyValuePair.Key + ":null");
                    }
                    else
                    {
                        string key = keyValuePair.Key;
                        var va = keyValuePair.Value;

                        if (va is string)
                        {
                            str += key + "\": \"" + va + "\",\"";
                        }
                        else if (va is bool)
                        {
                            str += key + "\":" + va.ToString().ToLower() + ",\"";
                        }
                        else if (va is int || va is float || va is double || va is long)
                        {
                            str += key + "\": " + va + ",\"";
                        }
                        else if (va is List<string> list)
                        {
                            str += key + "\":[";
                            for (int i = 0; i < list.Count; i++)
                            {
                                str += "\"" + list[i] + "\",";
                            }

                            if (list.Count > 0)
                            {
                                str = str.Substring(0, str.Length - 1);
                            }

                            str += "],\"";
                        }
                        else
                        {
                            Log.Info(va.GetType());
                        }
                    }
                }

                int l = str.Length - 2;
                str = str.Substring(0, l);

                str += "}";
            }
            else
            {
                str = "{}";
            }

//            string temp = " {\"sign\": \"" + sign + "\",\"inmap\": " + str + ",\"inlist\": null}";
            string temp = str;
            return temp;
        }

        /// <summary>
        /// 订阅web回调事件
        /// </summary>
        /// <param name="urlName"></param>
        /// <param name="handler"></param>
        public void Subscribe(string urlName, EventHandler<GameEventArgs> handler)
        {
            GameEntry.Event.Subscribe(WebUtility.GetIntHash(urlName), handler);
        }

        /// <summary>
        /// 取消订阅web回调事件
        /// </summary>
        /// <param name="urlName"></param>
        /// <param name="handler"></param>
        public void UnSubscribe(string urlName, EventHandler<GameEventArgs> handler)
        {
            GameEntry.Event.Unsubscribe(WebUtility.GetIntHash(urlName), handler);
        }

        /// <summary>
        /// 加载资源成功回调
        /// </summary>
        /// <param name="assetname"></param>
        /// <param name="asset"></param>
        /// <param name="duration"></param>
        /// <param name="userdata"></param>
        private void LoadAssetsSuccess(string assetname, object asset, float duration, object userdata)
        {
            if (userdata != this)
            {
                return;
            }

            TextAsset result = (TextAsset) asset;
            m_Po = new PropertyOperation(result.text);
            m_IsLoaded = true;
        }

        /// <summary>
        /// 加载资源失败回调
        /// </summary>
        /// <param name="assetname"></param>
        /// <param name="progress"></param>
        /// <param name="userdata"></param>
        private void LoadAssetsFailure(string assetname, float progress, object userdata)
        {
            Log.Warning("LoadAssetsFailure：" + assetname);
        }
    }
}